/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.contacts.common.list;

import android.content.AsyncTaskLoader;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.Handler;
import android.provider.ContactsContract.Directory;
import android.text.TextUtils;
import com.android.dialer.R;
import com.android.contacts.common.compat.DirectoryCompat;
import com.android.dialer.common.LogUtil;
import com.android.dialer.util.PermissionsUtil;

/** A specialized loader for the list of directories, see {@link Directory}. */
public class DirectoryListLoader extends AsyncTaskLoader<Cursor> {

  public static final int SEARCH_MODE_NONE = 0;
  public static final int SEARCH_MODE_DEFAULT = 1;
  public static final int SEARCH_MODE_CONTACT_SHORTCUT = 2;
  public static final int SEARCH_MODE_DATA_SHORTCUT = 3;
  // This is a virtual column created for a MatrixCursor.
  public static final String DIRECTORY_TYPE = "directoryType";
  private static final String[] RESULT_PROJECTION = {
    Directory._ID, DIRECTORY_TYPE, Directory.DISPLAY_NAME, Directory.PHOTO_SUPPORT,
  };
  private final ContentObserver mObserver =
      new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange) {
          forceLoad();
        }
      };
  private int mDirectorySearchMode;
  private boolean mLocalInvisibleDirectoryEnabled;
  private MatrixCursor mDefaultDirectoryList;

  public DirectoryListLoader(Context context) {
    super(context);
  }

  public void setDirectorySearchMode(int mode) {
    mDirectorySearchMode = mode;
  }

  /**
   * A flag that indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should be
   * included in the results.
   */
  public void setLocalInvisibleDirectoryEnabled(boolean flag) {
    this.mLocalInvisibleDirectoryEnabled = flag;
  }

  @Override
  protected void onStartLoading() {
    if (PermissionsUtil.hasContactsReadPermissions(getContext())) {
      getContext()
          .getContentResolver()
          .registerContentObserver(DirectoryQuery.URI, false, mObserver);
    } else {
      LogUtil.w("DirectoryListLoader.onStartLoading", "contacts permission not available.");
    }
    forceLoad();
  }

  @Override
  protected void onStopLoading() {
    getContext().getContentResolver().unregisterContentObserver(mObserver);
  }

  @Override
  public Cursor loadInBackground() {
    if (mDirectorySearchMode == SEARCH_MODE_NONE) {
      return getDefaultDirectories();
    }

    MatrixCursor result = new MatrixCursor(RESULT_PROJECTION);
    Context context = getContext();
    PackageManager pm = context.getPackageManager();
    String selection;
    switch (mDirectorySearchMode) {
      case SEARCH_MODE_DEFAULT:
        selection = null;
        break;

      case SEARCH_MODE_CONTACT_SHORTCUT:
        selection = Directory.SHORTCUT_SUPPORT + "=" + Directory.SHORTCUT_SUPPORT_FULL;
        break;

      case SEARCH_MODE_DATA_SHORTCUT:
        selection =
            Directory.SHORTCUT_SUPPORT
                + " IN ("
                + Directory.SHORTCUT_SUPPORT_FULL
                + ", "
                + Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY
                + ")";
        break;

      default:
        throw new RuntimeException("Unsupported directory search mode: " + mDirectorySearchMode);
    }
    Cursor cursor = null;
    try {
      cursor =
          context
              .getContentResolver()
              .query(
                  DirectoryQuery.URI,
                  DirectoryQuery.PROJECTION,
                  selection,
                  null,
                  DirectoryQuery.ORDER_BY);

      if (cursor == null) {
        return result;
      }

      while (cursor.moveToNext()) {
        long directoryId = cursor.getLong(DirectoryQuery.ID);
        if (!mLocalInvisibleDirectoryEnabled && DirectoryCompat.isInvisibleDirectory(directoryId)) {
          continue;
        }
        String directoryType = null;

        String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
        int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
        if (!TextUtils.isEmpty(packageName) && typeResourceId != 0) {
          try {
            directoryType = pm.getResourcesForApplication(packageName).getString(typeResourceId);
          } catch (Exception e) {
            LogUtil.e(
                "ContactEntryListAdapter.loadInBackground",
                "cannot obtain directory type from package: " + packageName);
          }
        }
        String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
        int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT);
        result.addRow(new Object[] {directoryId, directoryType, displayName, photoSupport});
      }
    } catch (RuntimeException e) {
      LogUtil.w(
          "ContactEntryListAdapter.loadInBackground", "runtime exception when querying directory");
    } finally {
      if (cursor != null) {
        cursor.close();
      }
    }

    return result;
  }

  private Cursor getDefaultDirectories() {
    if (mDefaultDirectoryList == null) {
      mDefaultDirectoryList = new MatrixCursor(RESULT_PROJECTION);
      mDefaultDirectoryList.addRow(
          new Object[] {Directory.DEFAULT, getContext().getString(R.string.contactsList), null});
      mDefaultDirectoryList.addRow(
          new Object[] {
            Directory.LOCAL_INVISIBLE,
            getContext().getString(R.string.local_invisible_directory),
            null
          });
    }
    return mDefaultDirectoryList;
  }

  @Override
  protected void onReset() {
    stopLoading();
  }

  private static final class DirectoryQuery {

    public static final Uri URI = DirectoryCompat.getContentUri();
    public static final String ORDER_BY = Directory._ID;

    public static final String[] PROJECTION = {
      Directory._ID,
      Directory.PACKAGE_NAME,
      Directory.TYPE_RESOURCE_ID,
      Directory.DISPLAY_NAME,
      Directory.PHOTO_SUPPORT,
    };

    public static final int ID = 0;
    public static final int PACKAGE_NAME = 1;
    public static final int TYPE_RESOURCE_ID = 2;
    public static final int DISPLAY_NAME = 3;
    public static final int PHOTO_SUPPORT = 4;
  }
}
